Skip to content

fix(edit-content): refresh History, Comments and Reference Pages after save #36617 - #36901

Open
adrianjm-dotCMS wants to merge 5 commits into
mainfrom
adrianjm-dotCMS/history-comments-side-panel-not-refreshing-when
Open

fix(edit-content): refresh History, Comments and Reference Pages after save #36617#36901
adrianjm-dotCMS wants to merge 5 commits into
mainfrom
adrianjm-dotCMS/history-comments-side-panel-not-refreshing-when

Conversation

@adrianjm-dotCMS

@adrianjm-dotCMS adrianjm-dotCMS commented Aug 5, 2026

Copy link
Copy Markdown
Member

Fixes #36617

Proposed Changes

The sidebar's History, Comments and Reference Pages stayed stale after a save/publish and needed a manual page reload. There were two independent root causes.

  • The refresh effects lived on a component that gets destroyed. They sat on DotEditContentSidebarComponent, which the layout's @if destroys and recreates — taking the effects with it. Moved into store-level withHooks({ onInit }) in withActivities and withInformation, so they live as long as the store does. This matches the existing lock / workflow / history features.

  • withHistory did not recognise a newly minted version. Its memo only invalidated on ${identifier}:${languageId}, but a save mints a new inode under the same identifier and locale, so loadVersions never re-fired. The symptom differed per host, which is why it looked like two separate bugs:

Screen.Recording.2026-08-05.at.3.47.52.PM.mov
Full-screen Dialog
Navigates on save? Yes → runs initializeExistingContent No
Effect on the list Emptied (versions: []) Left untouched
What you saw "it went blank" "it didn't update"

Added two invalidation signals: a cleared list (status === INIT, ignored mid-reload so it cannot fetch the identifier being left behind) and a live-inode baseline that only advances when not viewing a historical version, so browsing versions — and returning from them — does not refetch.

  • Fixed signal granularity in both effects. They read store.uiState(), i.e. the whole slice. Every writer replaces that object wholesale, so the effects refetched on unrelated UI changes — including the view flip loadVersions performs internally, costing 3–4 redundant requests per save. Now they read the store.uiState.isSidebarOpen() leaf.

Checklist

  • Tests
  • Translations
  • Security Implications Contemplated (none — no new endpoints, inputs or permissions; only client-side refresh timing)

Additional Info

Tests: 2180 passing across 111 suites in edit-content; lint and typecheck clean. New coverage includes publish-in-dialog, publish-while-comparing, the mid-reload case, historical/compare round trips, and a regression test for the signal-granularity fix (verified it fails against the previous code).

One existing test changed expectationshould not reload anything when only the version inode changes asserted that moving only the inode does not reload, which was literally the bug. Rewritten as should reload versions but not push publish history when the live inode moves. This is safe because browsing versions always goes through loadVersionContent, which sets isViewingHistoricalVersion; a bare inode move only happens on save/publish. The browsing cases are now covered by dedicated tests that set the realistic state.

Known follow-ups, deliberately out of scope:

  • Push Publish History still does not reload on publish (kept the original per-identifier scoping).
  • clearVersions() / resetVersions() / clearPushPublishHistory() / resetPushPublishHistory() in history.feature.ts have no production call sites — dead code worth removing separately.

🤖 Generated with Claude Code

…r save #36617

The sidebar's History, Comments and Reference Pages stayed stale after a
save/publish, requiring a manual page reload. Two root causes:

- The refresh effects lived on DotEditContentSidebarComponent, which the
  layout's @if destroys and recreates, taking the effects with it. Moved
  them into store-level withHooks({onInit}) in withActivities and
  withInformation, matching the existing lock/workflow/history features.

- withHistory only invalidated its memo on `${identifier}:${languageId}`,
  but a save mints a new inode under the SAME identifier and locale, so
  loadVersions never re-fired. Full-screen rendered an empty list
  (initializeExistingContent had already cleared it); the dialog host,
  which never navigates, rendered a stale one. Added two invalidation
  signals: a cleared list (status INIT, ignored mid-reload so it cannot
  fetch the identifier being left behind) and a live-inode baseline that
  only advances when not viewing a historical version, so browsing
  versions and returning from them does not refetch.

Both effects now read the isSidebarOpen leaf instead of uiState(): every
writer replaces that slice wholesale, so depending on the object refetched
on unrelated UI changes, including the view flip loadVersions performs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Claude finished @adrianjm-dotCMS's task in 12m 19s —— View job


Code Review — PR #36901

  • Read the diff (production code + tests)
  • Analyze root-cause fixes (effects moved to store hooks, withHistory invalidation, signal granularity)
  • Check for bugs, races, edge cases
  • Post review

I traced all three fixes against the store's feature composition, the initializeExistingContent reload path, the workflow-save path, and the compare/historical flows. The reasoning in the code comments holds up against the actual state transitions.

New Issues

  • 🟡 Medium: store/features/history/history.feature.ts:824 — The newLiveVersion check is suppressed whenever isViewingHistoricalVersion is true, and loadedLiveInode only advances in the same guard. dot-edit-content-sidebar.component.html:118 renders the workflow-actions block gated only on showWorkflowActions(), not on historical view (unlike the lock section at line 87, which does exclude historical). Assumption: a workflow action can still be fired while a historical version is on screen. Failure scenario: fire save/publish while viewing a historical version → contentlet.inode moves forward but isViewingHistoricalVersion is still true, so loadVersions does not re-fire and loadedLiveInode is never updated to the new inode; the version list stays stale for the rest of the session. What to verify: whether workflow actions are actually reachable in historical view — if the block should be hidden there (matching the lock section), this is moot; if not, it's a genuine stale-list gap. This is adjacent to the "Push Publish History still does not reload" follow-up you already scoped out, so it may belong in the same follow-up. Fix this →

Notes (non-blocking)

  • The signal-granularity fix (store.uiState.isSidebarOpen() deep-signal leaf instead of store.uiState()) is correct — uiState is a withState slice so the DeepSignal accessor is valid, and it avoids the wholesale-replace refetch storm from the internal view flip. Good catch, and the regression test that verifies it fails against the old code is the right guard.
  • The versionsCleared / isReloading invariant is sound: state: LOADING is written only by the two content.feature.ts initialize methods (lines 197, 276) and the error path navigates away (router.navigate(['/c/content']) at line 401), which tears down the store — so the deferred cleared-list fetch can't hang forever, and no loader resets to INIT to create a fetch loop. The documented invariant matches the code.
  • Moving the refresh effects into store-level withHooks({ onInit }) is the correct fix for the destroyed-component root cause and matches the existing lock/workflow/history features. Feature order in edit-content.store.ts (withUIwithContent → … → withActivitieswithHistory) means the methods and uiState slice these effects reference are all defined before the hooks run.
  • The two dead-method cleanups (clearVersions/resetVersions/etc.) you flagged as out-of-scope are indeed unreferenced in production — reasonable to defer.

Overall this is a solid, well-tested fix. No blocking issues. The single Medium is a scoped-edge question, not a regression in the happy path the PR targets.

· adrianjm-dotCMS/history-comments-side-panel-not-refreshing-when

…+ e2e #36617

The feature specs verify the store effects against a synthetic store with no
component mounted, so they cannot catch the regression this fix addresses: the
effects used to live on DotEditContentSidebarComponent, which the layout's @if
destroys and recreates. Moving them back would leave every feature spec green.

Two layers close that gap, both parameterized over the full-screen and dialog
hosts since the bug had a different face in each:

- Integration (dot-edit-content.layout.component.spec.ts): real store mounted in
  the real layout with the sidebar as a MockComponent. Asserts the fetches happen
  while the sidebar is not rendered at all, that they survive the sidebar being
  destroyed and recreated, and that a save minting a new inode refreshes without
  any re-initialization (the dialog path). Verified these fail when the store
  hooks are removed.

- E2E (apps/dotcms-ui-e2e/.../sidebar/history-refresh.spec.ts): publishes and
  comments through the UI and asserts History/Comments update with no reload,
  in full-screen and in the dialog (reached via the relationship field's "New
  Content", which needs no page/template fixture). Verified against the pre-fix
  code: full-screen reproduced the empty list (expected 2, got 0) and the dialog
  reproduced the stale list (expected 2, got 1).

Dialog comments are deliberately not covered — the comment form is hidden for
content opened as 'new', which is the only mode that entry point offers. It
needs the UVE pencil flow and a page fixture; documented in the spec.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
adrianjm-dotCMS and others added 2 commits August 5, 2026 23:04
`nx format:check` — the CI's format-test goal — flagged this file. The
lint-staged hook ran `nx format:write` on it at commit time but left it
unformatted, so the check only surfaced in the pipeline.

Formatting only; no test logic changed. 2186 tests still pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

History & Comments side panel not refreshing when editing via UVE (works via content search)

1 participant